#include <yunpan.h>
#include "head.h"

int getMyIdx(task_t *pTask, char **goalIdx);

int mkNewDir(task_t *pTask)
{
    char *cond = strtok(pTask->buf, " ");//命令，cond中内容应为cd
    char *dirName = strtok(NULL, " ");

    char sql[1024] = {0};
    sprintf(sql, "insert into dir (Name, Type, User, Pre_idx, md5)  values ('%s' ,'dir','%s','%s','NULL')"
            , dirName, pTask->user, pTask->curDir->Idx);
    puts(sql);
    int qret = mysql_query(pTask->pmysql, sql);
    if(qret == 0)
    {
        printf("Create newUserDir Success!\n");
        return 0;
    }
    else
    {
        printf("Error: %s\n", mysql_error(pTask->pmysql));
        return -1;
    }
}

int removeFile(task_t *pTask){//删除目标文件
    //removeFile argv[1]
    //char buf[1024];
    char delim[10] = " ";
    char *token1,*token2;
    int ret;
    token1 = strtok(pTask->buf,delim);
    token2 = strtok(NULL,delim);//分割出文件名
    struct stat fileinfo;         //定义文件属性结构体存储要删除文件属性
    ret = stat(token2,&fileinfo);//将目标文件属性存入结构体
    while(1){
        if(unlink(token2) < 0){
            printf("RMOVE ERROR!");
            break;
        }
        unlink(token2);
        if(fileinfo.st_nlink == 0){      //判断文件上是否还有链接，没有则删除成功
            printf("RMOVE COMPLETED!\n");
            break;
        }
    }
}

int cd(task_t *pTask) {
    char *cond = strtok(pTask->buf, " ");//命令，cond中内容应为cd
    char *goalDir = strtok(NULL, " ");
    
    if(strcmp(goalDir, "..") == 0 && strcmp(pTask->curDir->Pre_idx, "0") != 0)
    {
        char sql[1024] ={0};
        sprintf(sql, "select * from dir where Pre_idx = '%s'", pTask->curDir->Pre_idx);
        mysql_query(pTask->pmysql, sql);
        MYSQL_RES *result = mysql_store_result(pTask->pmysql);
        MYSQL_ROW row = mysql_fetch_row(result);
        pTask->curDir->Idx = row[0];
        pTask->curDir->Name = row[1];
        pTask->curDir->Pre_idx = row[4];
    }
    else if(strcmp(goalDir, "~") == 0)
    {
        pTask->curDir->Name = pTask->user;
        pTask->curDir->Pre_idx = "0";
        getMyIdx(pTask, &pTask->curDir->Idx);
    }
    else
    {
        pTask->curDir->Name = goalDir;
        char *goalIdx;
        pTask->curDir->Pre_idx = pTask->curDir->Idx;
        getMyIdx(pTask, &goalIdx);
        pTask->curDir->Idx = goalIdx; 
    }
    puts("cd success");
    char *str = "cd success";
    send(pTask->netFd, str, strlen(str), 0);
}

int ls(task_t *pTask){ //打印当前目录
    
    char buf[1024] = {0}; //buf为用来存储当前目录路径的内存空间
    
    char sql[1024] = {0};
    //当前目录下的目录的Pre_idx 为当前目录的Idx
    sprintf(sql, "select * from dir where User = '%s' and Pre_idx = '%s'"
            , pTask->user, pTask->curDir->Idx);
    int qret = mysql_query(pTask->pmysql, sql);
    MYSQL_RES *result = mysql_store_result(pTask->pmysql);
    MYSQL_ROW row;
    while((row = mysql_fetch_row(result)) != NULL)
    {
        strcat(buf, row[1]);
        strcat(buf, "   ");
    }
    printf("current working directory: %s\n",buf);//打印路径
    send(pTask->netFd,buf,strlen(buf),0);
}


int downloadFile(task_t *pTask){
    //gets file1
    char *command = strtok(pTask->buf," ");//解析获取命令
    char *fileName = strtok(NULL," ");//解析获取文件名
    int length = strlen(fileName);
    
    //首先判断文件是否存在,文件存在是传输文件的必要条件！ 
    DIR *pdir = opendir(".");
    ERROR_CHECK(pdir, NULL, "open");
    struct dirent *pdirent;
    while ((pdirent = readdir(pdir)) != NULL) {
        if(!strcmp(pdirent->d_name, fileName)) {
            break;
        }
    }
    if ((pdirent = readdir(pdir)) == NULL) {
        puts("No such file or directory!");
        send(pTask->netFd, "No such file or directory!", 26, 0);
        return -1;
    }

    char pianyi[100]={0};
    recv(pTask->netFd,pianyi,100,0);//接收客户端发来的客户端本地文件的大小，也就是偏移量
    //服务端再把字符串类改回long类型
    long pianyilen=atoi(pianyi);//偏移量也有可能是0
    //printf("pianyilen = %d\n",pianyilen);

    train_t t;
    bzero(t.buf,sizeof(t.buf));
    t.dataLength = length;
    strcpy(t.buf,fileName);

    printf("length = %d,fileName = %s\n",length,fileName);
    
    int fd = open(fileName, O_RDWR);
    ERROR_CHECK(fd,-1,"open");
    // int ret = send(pTask->netFd,&t,sizeof(t.dataLength)+ t.dataLength,MSG_NOSIGNAL);//发送文件名
    // ERROR_CHECK(ret,-1,"send");
    //不再需要发送文件名，客户端自己获取
    //获取服务器文件总大小并发送
    struct stat statbuf;
    int ret = fstat(fd,&statbuf);//获取文件的总大小
    ERROR_CHECK(ret,-1,"fstat");
    t.dataLength = sizeof(statbuf.st_size);//把文件的大小装入小火车
    memcpy(t.buf,&statbuf.st_size,sizeof(statbuf.st_size));
    send(pTask->netFd,&t,sizeof(t.dataLength)+t.dataLength,MSG_NOSIGNAL);

    //对比进行判断
    long totalFileLen = statbuf.st_size;
    printf("pianyilen = %ld,totallen = %ld\n",pianyilen,totalFileLen);
    if (pianyilen < totalFileLen) {
        lseek(fd, pianyilen, SEEK_SET);
    }
    else {
        //printf("Recv success!\n");
        return 0;
    }

    char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    ERROR_CHECK(p,MAP_FAILED,"mmap");
    off_t total = pianyilen;
    while(total < statbuf.st_size){
        if(statbuf.st_size - total < sizeof(t.buf)){
            //最后一次发送
            t.dataLength = statbuf.st_size-total;
        }
        else{
            t.dataLength = sizeof(t.buf);
        }
        memcpy(t.buf,p+total,t.dataLength);//把数据装入火车车厢
        int ret = send(pTask->netFd,&t,sizeof(t.dataLength)+t.dataLength,MSG_NOSIGNAL);
        ERROR_CHECK(ret,-1,"send");
        total += t.dataLength;
    }
    munmap(p,statbuf.st_size);
    t.dataLength = 0;
    send(pTask->netFd,&t,sizeof(t.dataLength),0);
    //发送终止
    close(fd);
}
int recvn(int netFd,void *p, int n){
    int total = 0;
    int ret;
    char *pTmp = (char *)p;
    while(total < n){
        ret = recv(netFd,pTmp+total,n-total,0);
        ERROR_CHECK(ret,-1,"recv");
        total+= ret;
    }
    return 0;
}

int isNewFile(char *fileName, char *md5)
{
    char sql[1024] = {0};
    unsigned char MD[16];
    MD5((unsigned char*)fileName, strlen(fileName), MD);
    for(int i = 0; i < 16; ++i)
    {
        sprintf(md5 + i * 2, "%02x", MD[i]);
    }

    int fd = open(md5, O_RDONLY);
    printf("fd = %d\n", fd);
    return fd;
}

int addNewFile(task_t *pTask, char *fileName, char *md5)
{
    char sql[1024] = {0};
    sprintf(sql, "insert into dir (Name, Type, User, Pre_idx, md5)  values ('%s', 'file', '%s', '%s', '%s')"
            , fileName, pTask->user, pTask->curDir->Idx, md5);
    int qret = mysql_query(pTask->pmysql, sql);
    if(qret == 0)
    {
        printf("upload a file successfully!\n");
        return 0;
    }
    else
    {
        printf("Error: %s\n", mysql_error(pTask->pmysql));
        return -1;
    }
}

int uploadFile(task_t *pTask){
    int dataLength;
    char name[1024] = {0};
    int ret =recvn(pTask->netFd,&dataLength,sizeof(int));//先收火车头
    ERROR_CHECK(ret,-1,"recv");
    ret = recvn(pTask->netFd,name, dataLength);//再收文件名
    ERROR_CHECK(ret,-1,"recv");
    char md5[100] = {0};
    ret = isNewFile(name, md5);
    if(ret != -1)
    {
        puts("启动秒传上传");
    }
    else if(ret == -1)
    {
        int fd = open(md5, O_RDWR|O_CREAT, 0666);
        ERROR_CHECK(fd,-1,"open");
        char buf[1024] = {0};
        long fileSize;
        recvn(pTask->netFd,&dataLength,sizeof(int));//先收火车头
        recvn(pTask->netFd,&fileSize,sizeof(fileSize));//再收文件长度
        printf("fileSize = %ld\n", fileSize);
        //ftruncate(fd,fileSize);
        off_t downSize = 0;
        off_t lastSize = 0;
        off_t slice = fileSize/1000;
        struct timeval begTime,endTime;
        gettimeofday(&begTime,NULL);
        while(1){
            ret = recvn(pTask->netFd,&dataLength,sizeof(int));//先收火车头
            ERROR_CHECK(ret,-1,"recv");
            if(dataLength==0){
                break;
            }
            if(dataLength != 1000){
                printf("dataLength = %d\n", dataLength);
            }
            ret = recvn(pTask->netFd,buf,dataLength);
            ERROR_CHECK(ret,-1,"recv");
            downSize += dataLength;
            if(downSize-lastSize > slice){
                printf("%5.2lf%s\r", 100.0*downSize/fileSize,"%");
                fflush(stdout);
                lastSize = downSize;
            }
            write(fd,buf,dataLength);
        }
        printf("100.00%s\n", "%");
        gettimeofday(&endTime,NULL);
        printf("total time = %ld\n", 1000000*(endTime.tv_sec-begTime.tv_sec) + endTime.tv_usec-begTime.tv_usec);
    }
    addNewFile(pTask, name, md5);
}

void usrConnectRecord(task_t myTask){
    time_t now = time(NULL);
    struct tm * pTm = localtime(&now); 
    syslog(LOG_INFO,"netFd=%d %s %02d%02d %02d:%02d:%02d\n",myTask.netFd,"connect time:",pTm->tm_mon+1,
    pTm->tm_mday,pTm->tm_hour,pTm->tm_min,pTm->tm_sec); 
}
void usrCommandRecord(task_t myTask){
    syslog(LOG_INFO,"netFd=%d %s %s\n",myTask.netFd,"command:",myTask.buf); 
}